package jing.ej.generic.wildcard;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EmptyStackException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

// Stack without generic
public class Stack<E> {
	private Object[] elements;
	private int size = 0;
	private static final int DEFAULT_INITIAL_CAPACITY = 16;
	public Stack() {
		elements = new Object[DEFAULT_INITIAL_CAPACITY];
	}
	public void push(E e) {
		ensureCapacity();
		elements[size++] = e;
	}
	public E pop() {
		if (size == 0)
			throw new EmptyStackException();
		@SuppressWarnings("unchecked")
		E result = (E) elements[--size];
		elements[size] = null; // Eliminate obsolete reference
		return result;
	}
	
	// pushAll method without wildcard type - deficient
//	public void pushAll(Iterable<E> src) {
//		for(E e : src)
//			push(e);
//	}
	
	// Wildcard type for parameter that serves as an E producer
	public void pushAll(Iterable<? extends E> src) {
		for (E e : src)
			push(e);
	}
	
	// popAll method without wildcard type - deficient!
//	public void popAll(Collection<E> dst) {
//		while (!isEmpty())
//			dst.add(pop());
//	}
	
	// Wildcard type for parameter that serves as an E consumer
	public void popAll(Collection<? super E> dst) {
		while (!isEmpty())
			dst.add(pop());
	}
	
	public boolean isEmpty() {
		return size == 0;
	}
	private void ensureCapacity() {
		if (elements.length == size)
			elements = Arrays.copyOf(elements, 2 * size + 1);
	}
	
	public static void main(String[] args) {
		Stack<Number> stack = new Stack<Number>();
		
		List<Number> list = new ArrayList<Number>();
		stack.pushAll(list);
		
		List<Integer> list1 = new ArrayList<Integer>();
		stack.pushAll(list1);
		
		Set<Number> set = new HashSet<Number>();
		stack.popAll(set);
		
		Set<Object> set1 = new HashSet<Object>();
		stack.popAll(set1);
	}
}
